﻿Imports System.Math, System.Windows.Forms.DataVisualization.Charting
Module ZMainModule
    Public isLoad, isCal, isDraw As Boolean
    '导入数据点数量
    Public PointNum As Integer
    '所有的导入数据点
    Public dataPoint As New List(Of Points)
    '圆曲线 
    Public cirP As New CirPoint
    '缓曲线
    Public spiP As New SpiPoint
    '主点，包括起点终点
    Public keyPoint As New List(Of Points)
    '所有的里程点
    Public milePoints As New List(Of Points)

    Public Sub cal()
        '圆曲线与缓曲线的初始化
        'init()
        '与圆曲线相关的计算
        cirP.cal(dataPoint(0), dataPoint(1), dataPoint(2))
        '与缓曲线相关的计算
        spiP.cal(cirP.YZ, dataPoint(2), dataPoint(3))
        '获取所有的主点保存在keyPoint中
        getKeyPoint()
        '获取所有的里程点，保存在milePoints中
        getMilePoints(5, cirP, spiP, keyPoint(0), keyPoint(keyPoint.Count - 1))
        isCal = True
    End Sub

    'Public Sub init()
    '    For i As Integer = 0 To dataPoint.Count - 3
    '        If dataPoint(i + 1).LS = 0 Then
    '            cirP.startPoint = dataPoint(i)
    '            cirP.JD = dataPoint(i + 1)
    '            cirP.endPoint = dataPoint(i + 2)
    '        Else
    '            spiP.startPoint = dataPoint(i)
    '            spiP.JD = dataPoint(i + 1)
    '            spiP.endPoint = dataPoint(i + 2)
    '        End If
    '    Next
    'End Sub

    '保存图表
    Public Sub savePicture(chart1 As Chart)
        Dim save As New SaveFileDialog
        save.Filter = "BMP|*.bmp"
        save.FilterIndex = 0
        If save.ShowDialog = DialogResult.OK Then
            Try
                chart1.SaveImage(save.FileName, System.Drawing.Imaging.ImageFormat.Bmp)
                MsgBox("保存成功")
            Catch ex As Exception
                MsgBox("保存失败！")
                Exit Sub
            End Try
        End If
    End Sub

    '保存报告
    Public Sub saveReport(textbox1 As TextBox)
        Dim dataText = textbox1.Text
        Dim save As New SaveFileDialog
        save.Filter = "TEXT|*.txt|ALL FILES|*.*"
        save.FilterIndex = 0
        If save.ShowDialog = DialogResult.OK Then
            Try
                System.IO.File.WriteAllText(save.FileName, dataText)
            Catch ex As Exception
                MsgBox("保存失败！")
                Exit Sub
            End Try
        End If
    End Sub

    '获取坐标方位角，弧度制
    Public Function getAzimuth(startPoint As Points, endPoint As Points) As Double
        Dim dx, dy As Double
        dx = endPoint.x - startPoint.x
        dy = endPoint.y - startPoint.y
        If dx = 0 Then
            If dy > 0 Then
                Return 0.5 * PI
            ElseIf dy < 0 Then
                Return 1.5 * PI
            End If
        End If

        'Dim alpha = Atan2(dy, dx)
        Dim alpha = Atan(dy / dx)
        'If dx > 0 And dy > 0 Then
        '    Return alpha
        'ElseIf dx < 0 And dy > 0 Then
        '    Return PI - alpha
        'ElseIf dx < 0 And dy < 0 Then
        '    Return PI + alpha
        'ElseIf dx > 0 And dy < 0 Then
        '    Return 2 * PI - alpha
        'End If

        If dx > 0 Then
            Return alpha
        ElseIf dx < 0 Then
            Return alpha + PI
        End If


        Return Nothing
    End Function

    '获取两点间的距离
    Public Function getKil(startPoint As Points, endPoint As Points) As Double
        Return Sqrt((endPoint.x - startPoint.x) ^ 2 + (endPoint.y - startPoint.y) ^ 2)
    End Function

    '读取数据
    Public Sub loadData()
        Dim open As New OpenFileDialog
        open.Filter = "TEXT|*.txt|ALL FILES|*.*"
        open.FilterIndex = 1
        If open.ShowDialog() = DialogResult.OK Then
            Try
                Form1.ZDataGridView1.DataSource = Nothing
                Form1.ZTextBox2.Text = ""
                Form1.ZChart1.Titles.Clear()
                Form1.ZChart1.ChartAreas.Clear()
                Form1.ZChart1.Series.Clear()
                Dim dataStr As String = System.IO.File.ReadAllText(open.FileName)
                dataStr = dataStr.Replace(vbCrLf, ",")
                dataStr = dataStr.Trim(",")
                Dim PointData() As String = dataStr.Split(",")
                PointNum = PointData.Length / 5
                dataPoint.Clear()
                milePoints.Clear()
                keyPoint.Clear()
                For i As Integer = 0 To PointNum - 1
                    Dim p As New Points
                    If i = 0 Then
                        p.label = "QD"
                    ElseIf i = PointNum - 1
                        p.label = "JD"
                    Else
                        p.label = "ZD"
                    End If
                    p.name = PointData(0 + i * 5)
                    p.x = PointData(1 + i * 5)
                    p.y = PointData(2 + i * 5)
                    p.R = PointData(3 + i * 5)
                    p.LS = PointData(4 + i * 5)
                    dataPoint.Add(p)
                Next
                isLoad = True
                isCal = False
                isDraw = False
            Catch ex As Exception
                MsgBox("数据导入失败！")
                Exit Sub
            End Try
        Else
            Exit Sub
        End If
    End Sub

    '获取主点数据
    Public Sub getKeyPoint()
        keyPoint.Add(dataPoint(0))
        keyPoint.Add(cirP.ZY)
        keyPoint.Add(cirP.QZ)
        keyPoint.Add(cirP.YZ)
        keyPoint.Add(spiP.ZH)
        keyPoint.Add(spiP.HY)
        keyPoint.Add(spiP.QZ)
        keyPoint.Add(spiP.YH)
        keyPoint.Add(spiP.HZ)
        keyPoint.Add(dataPoint(dataPoint.Count - 1))
    End Sub

    '显示结果数据
    Public Function table()
        Dim dtb As New DataTable
        dtb.Columns.Add("点名", Type.GetType("System.String"))
        dtb.Columns.Add("X(m)", Type.GetType("System.Double"))
        dtb.Columns.Add("Y(m)", Type.GetType("System.Double"))
        dtb.Columns.Add("标签", Type.GetType("System.String"))
        dtb.Columns.Add("里程", Type.GetType("System.Double"))
        Dim row As DataRow
        For i As Integer = 0 To PointNum - 1
            row = dtb.NewRow
            row("点名") = dataPoint(i).name
            row("X(m)") = dataPoint(i).x
            row("Y(m)") = dataPoint(i).y
            row("标签") = dataPoint(i).label
            ''计算导入数据点的里程
            'If i = 0 Then
            '    dataPoint(i).k = 0
            'ElseIf i = 1 Then
            '    dataPoint(i).k = getKil(dataPoint(0), dataPoint(1))
            'ElseIf i = 2 Then
            '    dataPoint(i).k = getKil(dataPoint(1), dataPoint(2)) + dataPoint(1).k
            'ElseIf i = 3 Then
            '    dataPoint(i).k = getKil(dataPoint(2), dataPoint(3)) + dataPoint(2).k
            'End If
            row("里程") = dataPoint(i).k
            dtb.Rows.Add(row)
        Next
        Return dtb
    End Function

    '获取直线上点的坐标
    Public Sub getCoor(p As Points, startpoint As Points, endpoint As Points)
        '坐标方位角
        Dim a As Double = getAzimuth(startpoint, endpoint)
        Dim dx, dy As Double

        If p.k < cirP.ZY.k Then
            dx = p.k * Cos(a)
            dy = p.k * Sin(a)
        ElseIf p.k > cirP.YZ.k And p.k < spiP.ZH.k Then
            dx = (p.k - cirP.YZ.k) * Cos(a)
            dy = (p.k - cirP.YZ.k) * Sin(a)
        ElseIf p.k > spiP.HZ.k Then
            dx = (p.k - spiP.HZ.k) * Cos(a)
            dy = (p.k - spiP.HZ.k) * Sin(a)
        End If
        p.x = startpoint.x + dx
        p.y = startpoint.y + dy
    End Sub

    '弧度转角度
    Public Function CDegree(rad As Double) As String
        rad = rad * 180 / PI
        Dim d, m As Integer
        Dim s As Double
        d = Int(rad)
        m = Int((rad - d) * 60)
        s = ((rad - d) * 60 - m) * 60
        While True
            If Not Round(s, 1) < 60 Then
                s -= 60
                m += 1
            Else
                Exit While
            End If
        End While

        While True
            If Not m < 60 Then
                m -= 60
                d += 1
            Else
                Exit While
            End If
        End While

        Return String.Format("{0}°{1}′{2:f1}″", d, m, s)

    End Function

    '报告
    Public Function report()
        Dim text As String = ""
        text &= "圆曲线要素计算成果" & vbCrLf
        text &= "--------------------------------------------" & vbCrLf
        text &= String.Format("{0}{1}{2}{3}{4}{5}{6}{7}", "点名", vbTab, "X(m)", vbTab, "Y(m)", vbTab, "里程", vbCrLf)
        text &= String.Format("{0}{1}{2:f3}{3}{4:f3}{5}{6:f1}{7}", cirP.ZY.name, vbTab, cirP.ZY.x, vbTab, cirP.ZY.y, vbTab, cirP.ZY.k, vbCrLf)
        text &= String.Format("{0}{1}{2:f3}{3}{4:f3}{5}{6:f1}{7}", cirP.QZ.name, vbTab, cirP.QZ.x, vbTab, cirP.QZ.y, vbTab, cirP.QZ.k, vbCrLf)
        text &= String.Format("{0}{1}{2:f3}{3}{4:f3}{5}{6:f1}{7}", cirP.YZ.name, vbTab, cirP.YZ.x, vbTab, cirP.YZ.y, vbTab, cirP.YZ.k, vbCrLf)
        text &= vbCrLf
        text &= String.Format("线路转角α：{0:f4}{1}", CDegree(cirP.alpha), vbCrLf)
        text &= String.Format("切线长T：{0:f4}{1}", cirP.T, vbCrLf)
        text &= String.Format("曲线长L：{0:f4}{1}", cirP.L, vbCrLf)
        text &= String.Format("切曲差q：{0:f4}{1}", cirP.q, vbCrLf)

        text &= vbCrLf

        text &= "缓曲线要素计算成果" & vbCrLf
        text &= "--------------------------------------------" & vbCrLf
        text &= String.Format("{0}{1}{2}{3}{4}{5}{6}{7}", "点名", vbTab, "X(m)", vbTab, "Y(m)", vbTab, "里程", vbCrLf)
        text &= String.Format("{0}{1}{2:f3}{3}{4:f3}{5}{6:f1}{7}", spiP.ZH.name, vbTab, spiP.ZH.x, vbTab, spiP.ZH.y, vbTab, spiP.ZH.k, vbCrLf)
        text &= String.Format("{0}{1}{2:f3}{3}{4:f3}{5}{6:f1}{7}", spiP.HY.name, vbTab, spiP.HY.x, vbTab, spiP.HY.y, vbTab, spiP.HY.k, vbCrLf)
        text &= String.Format("{0}{1}{2:f3}{3}{4:f3}{5}{6:f1}{7}", spiP.QZ.name, vbTab, spiP.QZ.x, vbTab, spiP.QZ.y, vbTab, spiP.QZ.k, vbCrLf)
        text &= String.Format("{0}{1}{2:f3}{3}{4:f3}{5}{6:f1}{7}", spiP.YH.name, vbTab, spiP.YH.x, vbTab, spiP.YH.y, vbTab, spiP.YH.k, vbCrLf)
        text &= String.Format("{0}{1}{2:f3}{3}{4:f3}{5}{6:f1}{7}", spiP.HZ.name, vbTab, spiP.HZ.x, vbTab, spiP.HZ.y, vbTab, spiP.HZ.k, vbCrLf)
        text &= vbCrLf
        text &= String.Format("线路转角α：{0:f4}{1}", CDegree(spiP.alpha), vbCrLf)
        text &= String.Format("切线长TH：{0:f4}{1}", spiP.TH, vbCrLf)
        text &= String.Format("曲线长LH：{0:f4}{1}", spiP.LH, vbCrLf)
        text &= String.Format("外矢距EH：{0:f4}{1}", spiP.EH, vbCrLf)
        text &= String.Format("切曲差q：{0:f4}{1}", spiP.q, vbCrLf)

        text &= vbCrLf

        text &= "里程点计算成果" & vbCrLf
        text &= "--------------------------------------------" & vbCrLf
        text &= String.Format("{0}{1}{2}{3}{4}{5}{6}{7}", "点名", vbTab, "X(m)", vbTab, "Y(m)", vbTab, "里程", vbCrLf)
        For i As Integer = 0 To milePoints.Count - 1
            text &= String.Format("{0}{1}{2:f3}{3}{4:f3}{5}{6:f1}{7}", milePoints(i).name, vbTab, milePoints(i).x, vbTab, milePoints(i).y, vbTab, milePoints(i).k, vbCrLf)
        Next
        Return text
    End Function

    '绘图
    Public Sub draw(chart1 As Chart)
        chart1.ChartAreas.Clear()
        chart1.Series.Clear()
        chart1.Titles.Clear()

        Dim t As New Title("里程点图")
        t.Font = New Font("黑体", 12)
        chart1.Titles.Add(t)
        Dim area1 As New ChartArea
        Dim x(dataPoint.Count - 1), y(dataPoint.Count - 1) As Double
        For i As Integer = 0 To dataPoint.Count - 1
            x(i) = dataPoint(i).x
            y(i) = dataPoint(i).y
        Next
        area1.AxisX.Title = "X坐标"
        area1.AxisY.Title = "Y坐标"

        area1.AxisX.Maximum = (x.Max \ 10 + 1) * 10
        area1.AxisX.Minimum = (x.Min \ 10 - 1) * 10
        area1.AxisY.Maximum = (y.Max \ 10 + 1) * 10
        area1.AxisY.Minimum = (y.Min \ 10 - 1) * 10

        area1.AxisX.MajorGrid.Enabled = False
        area1.AxisY.MajorGrid.Enabled = False

        chart1.ChartAreas.Add(area1)

        Dim series1 As New Series
        series1.ChartType = SeriesChartType.Line
        series1.Color = Color.Black
        series1.BorderWidth = 1
        series1.IsVisibleInLegend = False
        series1.ChartArea = area1.Name

        chart1.Series.Add(series1)
        For i As Integer = 0 To milePoints.Count - 1
            chart1.Series.Last.Points.AddXY(milePoints(i).x, milePoints(i).y)
        Next
        '显示所有的点，包括里程点、导入数据点,主点
        Dim series2(milePoints.Count + keyPoint.Count - 1 + 2) As Series
        For i As Integer = 0 To series2.Length - 1
            series2(i) = New Series
            series2(i).ChartType = SeriesChartType.Point
            series2(i).MarkerStyle = MarkerStyle.Circle
            series2(i).MarkerSize = 4
            series2(i).Color = Color.Blue
            series2(i).BorderWidth = 1
            If i <= milePoints.Count - 1 Then
                series2(i).Label = milePoints(i).name
            ElseIf i <= milePoints.Count + keyPoint.Count - 1
                series2(i).Label = keyPoint(i - milePoints.Count).name
            Else
                series2(i).Label = dataPoint((i + 1) - milePoints.Count - keyPoint.Count).name
            End If
            series2(i).IsVisibleInLegend = False
            series2(i).ChartArea = area1.Name
            chart1.Series.Add(series2(i))
            If i <= milePoints.Count - 1 Then
                chart1.Series.Last.Points.AddXY(milePoints(i).x, milePoints(i).y)
            ElseIf i <= keyPoint.Count + milePoints.Count - 1 Then
                chart1.Series.Last.Points.AddXY(keyPoint(i - milePoints.Count).x, keyPoint(i - milePoints.Count).y)
            Else
                chart1.Series.Last.Points.AddXY(dataPoint((i + 1) - milePoints.Count - keyPoint.Count).x, dataPoint((i + 1) - milePoints.Count - keyPoint.Count).y)
            End If
        Next
        isDraw = True
    End Sub

    '获取里程点
    Public Sub getMilePoints(interval As Double, cp As CirPoint, sp As SpiPoint, startpoint As Points, endpoint As Points)
        Dim sumKil As Double = sp.HZ.k + getKil(sp.HZ, endpoint)
        Dim pNum As Integer = sumKil \ interval
        For i As Integer = 0 To pNum - 1
            Dim p As New Points
            p.name = "K" & ((i + 1) * 10)
            p.k = interval * (i + 1)
            If p.k >= cp.ZY.k And p.k <= cp.YZ.k Then
                cp.getCoor(p.k, p)
            ElseIf p.k >= sp.ZH.k And p.k <= sp.HZ.k Then
                sp.getCoor(p.k, p)
            ElseIf p.k < cp.ZY.k Then
                getCoor(p, startpoint, cp.ZY)
            ElseIf p.k > cp.YZ.k And p.k < sp.ZH.k Then
                getCoor(p, cp.YZ, sp.ZH)
            ElseIf p.k > sp.HZ.k Then
                getCoor(p, sp.HZ, endpoint)
            End If
            milePoints.Add(p)
        Next
    End Sub

End Module

